extends EquipableComponent


class_name GunWeapon


## 枪口位置
@export var muzzle_marker: Node2D = null
## 子弹工厂
@export var bullet_factory: INodeFactory = null
## 子弹属性
@export var bullet_params: ProjectileResource = null


# 当前已经发射的子弹
var bullets: Array[Projectile] = []


func __check_exports() -> Dictionary:
    return IComponent.merge({
        "muzzle_marker": IComponent.find_child.bind(self, func(x): return x is Node2D, muzzle_marker),
        "bullet_factory": IComponent.find_child.bind(self, func(x): return x is INodeFactory, bullet_factory),
    }, super.__check_exports())

func cancel() -> void:
    for b in bullets.duplicate():
        __destroy_bullet(b)
    bullets.clear()
    super.cancel()

func spawn(arg: ProjectileResource) -> Projectile:
    var bullet: Projectile = bullet_factory.create()
    bullet.setup(arg)
    bullet.weapon = self
    bullet.event_hit_something.connect(__on_bullet_hit_something)
    bullet.event_hit_nothing.connect(__on_bullet_hit_nothing)
    bullet.event_hit_out_of_screen.connect(__on_bullet_hit_out_of_screen)

    bullets.append(bullet)
    return bullet

func attack() -> void:
    bullet_params.start_direction = Vector2.from_angle(muzzle_marker.global_rotation)
    bullet_params.start_position = muzzle_marker.global_position
    var bullet: Projectile = spawn(bullet_params)
    if CharacterUnit.hit_execute(__mount_character, bullet_params, bullet):
        __destroy_bullet(bullet)

func __destroy_bullet(bullet: Projectile) -> void:
    bullet.event_hit_nothing.disconnect(__on_bullet_hit_nothing)
    bullet.event_hit_something.disconnect(__on_bullet_hit_something)
    bullet.event_hit_out_of_screen.disconnect(__on_bullet_hit_out_of_screen)

    bullet.teardown()
    bullet_factory.destroy(bullet)
    bullets.erase(bullet)

func __on_bullet_hit_something(node: Projectile, body: Node2D, body_rid: RID, hit_direction: Vector2, hit_normal: Vector2) -> void:
    if CharacterUnit.hit_something(__mount_character, node, body, body_rid, hit_direction, hit_normal):
        return
    __destroy_bullet(node)

func __on_bullet_hit_nothing(node: Projectile) -> void:
    if CharacterUnit.hit_nothing(__mount_character, node):
        return
    __destroy_bullet(node)

func __on_bullet_hit_out_of_screen(node: Projectile, hit_direction: Vector2) -> void:
    if CharacterUnit.hit_out_of_screen(__mount_character, node, hit_direction):
        return
    __destroy_bullet(node)
